package TI;

import static org.mockito.Mockito.*;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
import Exceptions.NotEnoughStockException;
import Magnitudes.Litre;
import Magnitudes.Pesos;
import Products.Presentation;

public class StorehouseTest extends TestCase {

	Storehouse storehouseUnderTest;
	Address address = mock(Address.class);
	Presentation aPresentation = mock(Presentation.class);
	Presentation anotherPresentation = mock(Presentation.class);
	Presentation justAnotherPresentation = mock(Presentation.class);
	Exception exception;
	
	@Before
	public void setUp(){
		storehouseUnderTest = new Storehouse(address);
		when(aPresentation.compareTo(aPresentation)).thenReturn(0);
	}

	@Test
	public void testGivenAStorehouseWithoutAPresentationWhenAskedIsAvailableShouldReturnFalse(){
		assertFalse(storehouseUnderTest.isAvailable(aPresentation));
		assertFalse(storehouseUnderTest.isAvailable(anotherPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWhenPresentationsStockIsGreatThan0WhenAskedIsAvailableShouldReturnTrue(){
		storehouseUnderTest.receive(aPresentation, 1);
		storehouseUnderTest.receive(anotherPresentation, 10);
		assertTrue(storehouseUnderTest.isAvailable(aPresentation));
		assertTrue(storehouseUnderTest.isAvailable(anotherPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWhenPresentationsStockIs0WhenAskedIsAvailableShouldReturnFalse(){
		storehouseUnderTest.receive(aPresentation, 1);
		try {
			storehouseUnderTest.deliver(aPresentation, 1);
		} catch (NotEnoughStockException e) {
			e.printStackTrace();
		}
		assertFalse(storehouseUnderTest.isAvailable(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseThatNeverReceiveAPresentationWhenAskedForCurrentStockShouldReturn0(){
		assertEquals((Integer) 0, storehouseUnderTest.currentStock(aPresentation));
		assertEquals((Integer) 0, storehouseUnderTest.currentStock(justAnotherPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAReceivedPresentationWhenAskedForCurrentStockShouldReturnTheReceivedQuantity(){
		storehouseUnderTest.receive(aPresentation, 5);
		int expected = storehouseUnderTest.currentStock(aPresentation);
		assertEquals(5, expected);
	}
	
	@Test
	public void testGivenAStorehouseWithAReceivedPresentationWhenReceiveAgainAskedForCurrentStockShouldReturnTheSumQuantity(){
		storehouseUnderTest.receive(aPresentation, 5);
		storehouseUnderTest.receive(aPresentation, 3);
		int expected = storehouseUnderTest.currentStock(aPresentation);
		assertEquals(8, expected);
	}
	
	@Test
	public void testGivenAStorehouseWithAReceivedPresentationWhenDeliverAskedForCurrentStockShouldReturnTheSubQuantity(){
		storehouseUnderTest.receive(aPresentation, 5);
		try {
			storehouseUnderTest.deliver(aPresentation, 3);
		} catch (NotEnoughStockException e) {
			e.printStackTrace();
		}
		int expected = storehouseUnderTest.currentStock(aPresentation);
		assertEquals(2, expected);
	}
	
	@Test
	public void testGivenAStorehouseWithAReceivedPresentationWhenTryingToDeliverMoreThanReceivedShouldRaiseNotEnoughStockException(){
		
		storehouseUnderTest.receive(aPresentation, 5);		
		try{
			storehouseUnderTest.deliver(aPresentation, 6);
		} catch (NotEnoughStockException notEnoughStockException){
			exception = notEnoughStockException;
		}		
		assertNotNull(exception);
		assertTrue(exception.getMessage().contains("There is not enough stock to deliver the product"));
	}
	
	
	@Test
	public void testGivenAStorehouseWithoutAReceivedPresentationWhenTryingToDeliverItShouldRaiseNotEnoughStockException(){
		
		try{
			storehouseUnderTest.deliver(aPresentation, 1);
		} catch (NotEnoughStockException notEnoughStockException){
			exception = notEnoughStockException;
		}		
		assertNotNull(exception);
		assertTrue(exception.getMessage().contains("There is not enough stock to deliver the product"));
	}

	
	@Test
	public void testGivenAStorehouseWithoutAReceivedPresentationWhenSetMinimalStockWithAnyNumberAndIsAskedShouldReturnIsOnMinimalStock(){
		
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 0);		
		assertTrue(storehouseUnderTest.isOnMinimalStock(aPresentation));
	}
	
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatHasMoreItemsThanTheMinimalWhenAskedShouldReturnFalse(){
		
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 10);
		storehouseUnderTest.receive(aPresentation, 100);
		assertFalse(storehouseUnderTest.isOnMinimalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatHasLessItemsThanTheMinimalWhenAskedShouldReturnTrue(){
		
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.receive(aPresentation, 99);
		assertTrue(storehouseUnderTest.isOnMinimalStock(aPresentation));
	}
	
	
	@Test
	public void testGivenAStorehouseWithoutAReceivedPresentationAndNotSetedWhenAskedForAnyProductIsOnMinimalStockShouldReturnFalse(){
		assertFalse(storehouseUnderTest.isOnMinimalStock(aPresentation));
	}

	
	@Test
	public void testGivenAStorehouseWithoutAReceivedPresentationWhenSetCriticalStockWithAnyNumberAndIsAskedShouldReturnIsOnCriticalStock(){
		
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 0);
		
		assertTrue(storehouseUnderTest.isOnCriticalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithoutAReceivedPresentationAndNotSetedWhenAskedForAnyProductIsOnCriticalStockShouldReturnFalse(){
		assertFalse(storehouseUnderTest.isOnCriticalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatHasMoreItemsThanTheCriticalWhenAskedShouldReturnFalse(){
		
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 10);
		storehouseUnderTest.receive(aPresentation, 100);
		assertFalse(storehouseUnderTest.isOnCriticalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatHasLessItemsThanTheCriticalWhenAskedShouldReturnTrue(){
		
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.receive(aPresentation, 99);
		assertTrue(storehouseUnderTest.isOnCriticalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatIsOnMinimalStockWhenSetMinimalStockOnAHigherValueShouldNotAppearAsMinimal(){
		
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.receive(aPresentation, 99);
		assertTrue(storehouseUnderTest.isOnMinimalStock(aPresentation));
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 50);
		assertFalse(storehouseUnderTest.isOnMinimalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithAPresentationThatIsOnCriticalStockWhenSetCriticalStockOnAHigherValueShouldNotAppearAsCritical(){
		
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.receive(aPresentation, 99);
		assertTrue(storehouseUnderTest.isOnCriticalStock(aPresentation));
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 50);
		assertFalse(storehouseUnderTest.isOnCriticalStock(aPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithoutASetedMinimalsPresentationsWhenAskedForMinimalStockShouldReturnAnEmptyList(){
		assertTrue(storehouseUnderTest.minimalStockPresentations().isEmpty());
	}
	
	@Test
	public void testGivenAStorehouseWithPresentationsThatSomeAreMinimalWhenAskedForMinimalStockShouldReturnThoseThatAreMinimal(){
		
		storehouseUnderTest.setMinimalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.setMinimalStockForPresentation(anotherPresentation, 100);
		assertTrue(storehouseUnderTest.minimalStockPresentations().containsKey(aPresentation));
		assertTrue(storehouseUnderTest.minimalStockPresentations().containsKey(anotherPresentation));
	}
	
	@Test
	public void testGivenAStorehouseWithoutASetedCriticalsPresentationsWhenAskedForCriticalStockShouldReturnAnEmptyList(){
		assertTrue(storehouseUnderTest.criticalStockPresentations().isEmpty());
	}
	
	@Test
	public void testGivenAStorehouseWithPresentationsThatSomeAreCriticalWhenAskedForCriticalStockShouldReturnThoseThatAreCritical(){
		
		storehouseUnderTest.setCriticalStockForPresentation(aPresentation, 100);
		storehouseUnderTest.setCriticalStockForPresentation(anotherPresentation, 100);
		
		assertTrue(storehouseUnderTest.criticalStockPresentations().containsKey(aPresentation));
		assertTrue(storehouseUnderTest.criticalStockPresentations().containsKey(anotherPresentation));
	
	}
	
}
